#pragma once
#ifndef _MYVECTOR_H
#define _MYVECTOR_H

#include <assert.h>
#include <iostream>


template <typename T>
class MyVector {

private:
	int vec_capacity;
	int vec_size;
	T* myvector;

public:
	MyVector(const int num) :vec_capacity(num) {
		assert(num>0);
		vec_size = 0;
		myvector = new T[vec_capacity];
	}
	~MyVector() {
		delete[] myvector;
	}
	void push_back(const T& in);
	void pop_back();
	const int size() const;
	bool empty() const;
	void clear();
	const T& front() const;
	const T& back() const;
	const T& operator[] (const int idx);
	const int capacity() const;
};

template <typename T>
void MyVector<T>::push_back(const T& in) {
	if (vec_size == vec_capacity) {
		T* newvector=new T[vec_capacity * 2];
		for (int i = 0; i < vec_capacity; i++) {
			newvector[i] = myvector[i];
		}
		delete [] myvector;
		myvector = newvector;
		vec_capacity =vec_capacity * 2;
	}
	myvector[vec_size++] = in;
}

template <typename T>
void MyVector<T>::pop_back() {
	vec_size--;
}

template <typename T>
const int MyVector<T>::size() const {
	return vec_size;
}

template <typename T>
bool MyVector<T>::empty() const{
	return vec_size == 0;
}

template <typename T>
void MyVector<T>::clear() {
	vec_size = 0;
}

template <typename T>
const T& MyVector<T>::front() const {
	if (!empty()) {
		return myvector[0];
	}
	else {
		throw "The vector is empty! No front element.";
	}
}

template <typename T>
const T& MyVector<T>::back() const {
	if (!empty()) {
		return myvector[vec_size-1];
	}
	else {
		throw "The vector is empty! No back element.";
	}
}

template <typename T>
const T& MyVector<T>::operator[] (const int idx) {
	assert(idx >= 0);
	if (idx < vec_size) {
		return myvector[idx];
	}
	else {
		throw "Out of index!";
	}
}

template <typename T>
const int MyVector<T>::capacity() const {
	return vec_capacity;
}
#endif